]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
Attach dialogs to windows with visual effects
authorMaxim Ermilov <zaspire@rambler.ru>
Sat, 11 Sep 2010 01:30:50 +0000 (05:30 +0400)
committerMaxim Ermilov <zaspire@rambler.ru>
Sat, 11 Sep 2010 01:39:57 +0000 (05:39 +0400)
Override the new mutter preference /apps/mutter/general/attach_modal_dialogs
to attach modal dialogs to their parent window. Animate the modal dialogs
expanding from the top of the parent window. Slowly dim the parent window
after the dialog comes up.
https://bugzilla.gnome.org/show_bug.cgi?id=612726

data/Makefile.am
data/gnome-shell.schemas
data/shaders/dim-window.glsl [new file with mode: 0644]
js/ui/windowManager.js
src/gnome-shell-plugin.c

index 5d54a5bbf070fc7166ab25d8ccd01b61a17147a9..1f894f954d0b1c195cb3eb44bc26e287e07bb49f 100644 (file)
@@ -70,6 +70,10 @@ menudir = $(sysconfdir)/xdg/menus
 menu_DATA = \
        gs-applications.menu
 
+shadersdir = $(pkgdatadir)/shaders
+shaders_DATA = \
+       shaders/dim-window.glsl
+
 install-data-local:
        GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(srcdir)/$(gconfschema_DATA)
 
index 72c4751e980701f7fa4468cded582de1b28d67aa..d6a7dbfe675514770e54ea66c73eeb7a42ddf68f 100644 (file)
@@ -2,6 +2,21 @@
     <schemalist>
 
       <!-- Metacity overrides -->
+      <schema>
+        <key>/schemas/desktop/gnome/shell/windows/attach_modal_dialogs</key>
+        <applyto>/desktop/gnome/shell/windows/attach_modal_dialogs</applyto>
+        <owner>gnome-shell</owner>
+        <type>bool</type>
+        <default>true</default>
+        <locale name="C">
+          <short>Attach modal dialog to the parent window</short>
+          <long>
+             This key overrides /apps/mutter/general/attach_modal_dialogs when
+             running GNOME Shell.
+          </long>
+        </locale>
+      </schema>
+
       <schema>
         <key>/schemas/desktop/gnome/shell/windows/button_layout</key>
         <applyto>/desktop/gnome/shell/windows/button_layout</applyto>
diff --git a/data/shaders/dim-window.glsl b/data/shaders/dim-window.glsl
new file mode 100644 (file)
index 0000000..9099b04
--- /dev/null
@@ -0,0 +1,26 @@
+#version 100
+uniform sampler2D sampler0;
+uniform float fraction;
+uniform float height;
+const float c = -0.2;
+const float border_max_height = 60.0;
+
+mat4 contrast = mat4 (1.0 + c, 0.0, 0.0, 0.0,
+                      0.0, 1.0 + c, 0.0, 0.0,
+                      0.0, 0.0, 1.0 + c, 0.0,
+                      0.0, 0.0, 0.0, 1.0);
+vec4 off = vec4(0.633, 0.633, 0.633, 0);
+void main()
+{
+  vec4 color = texture2D(sampler0, gl_TexCoord[0].st);
+  float y = height * gl_TexCoord[0][1];
+
+  // To reduce contrast, blend with a mid gray
+  gl_FragColor = color * contrast - off * c;
+
+  // We only fully dim at a distance of BORDER_MAX_HEIGHT from the edge and
+  // when the fraction is 1.0. For other locations and fractions we linearly
+  // interpolate back to the original undimmed color.
+  gl_FragColor = color + (gl_FragColor - color) * min(y / border_max_height, 1.0);
+  gl_FragColor = color + (gl_FragColor - color) * fraction;
+}
index 6d0ea4411ff56dfca003d93332eafac609c8f947..8b96bb2beb4eb77b752cb6a57b3c134ceb5056ee 100644 (file)
@@ -1,6 +1,8 @@
 /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 
 const Clutter = imports.gi.Clutter;
+const GLib = imports.gi.GLib;
+const Gio = imports.gi.Gio;
 const Lang = imports.lang;
 const Meta = imports.gi.Meta;
 const St = imports.gi.St;
@@ -11,6 +13,68 @@ const Main = imports.ui.main;
 const Tweener = imports.ui.tweener;
 
 const WINDOW_ANIMATION_TIME = 0.25;
+const DIM_TIME = 0.500;
+const UNDIM_TIME = 0.250;
+
+var dimShader = undefined;
+
+function getDimShader() {
+    if (dimShader === null)
+        return null;
+    if (!dimShader) {
+        let [success, source, length] = GLib.file_get_contents(global.datadir +
+                                                               '/shaders/dim-window.glsl');
+        try {
+            let shader = new Clutter.Shader();
+            shader.set_fragment_source(source, -1);
+            shader.compile();
+
+            dimShader = shader;
+        } catch (e) {
+            log(e.message);
+            dimShader = null;
+        }
+    }
+    return dimShader;
+}
+
+function WindowDimmer(actor) {
+    this._init(actor);
+}
+
+WindowDimmer.prototype = {
+    _init: function(actor) {
+        this.actor = actor;
+    },
+
+    set dimFraction(fraction) {
+        this._dimFraction = fraction;
+        let shader = getDimShader();
+        if (!Meta.prefs_get_attach_modal_dialogs() || !shader) {
+            this.actor.set_shader(null);
+            return;
+        }
+        if (fraction > 0.01) {
+            this.actor.set_shader(shader);
+            this.actor.set_shader_param_float('height', this.actor.get_height());
+            this.actor.set_shader_param_float('fraction', fraction);
+        } else
+            this.actor.set_shader(null);
+    },
+
+    get dimFraction() {
+        return this._dimFraction;
+    },
+
+    _dimFraction: 0.0
+};
+
+function getWindowDimmer(texture) {
+    if (!texture._windowDimmer)
+        texture._windowDimmer = new WindowDimmer(texture);
+
+    return texture._windowDimmer;
+}
 
 function WindowManager() {
     this._init();
@@ -147,7 +211,75 @@ WindowManager.prototype = {
     _unmaximizeWindowDone : function(shellwm, actor) {
     },
 
+    _parentHasOtherAttachedDialog: function(parent, self) {
+        var count = 0;
+        parent.foreach_transient(function(win) {
+            if (win.get_window_type() == Meta.CompWindowType.MODAL_DIALOG && win != self)
+                count++;
+            return false;
+        });
+        return count != 0;
+    },
+
+    _dimParentWindow: function(actor) {
+        let meta = actor.get_meta_window();
+        let parent = meta.get_transient_for();
+        if (!parent)
+            return;
+        let parentActor = parent.get_compositor_private();
+        if (!parentActor)
+            return;
+        if (!this._parentHasOtherAttachedDialog(parent, meta)) {
+            let texture = parentActor.get_texture();
+            Tweener.addTween(getWindowDimmer(texture),
+                             { dimFraction: 1.0,
+                               time: DIM_TIME,
+                               transition: 'linear'
+                             });
+        }
+    },
+
+    _undimParentWindow: function(actor) {
+        let meta = actor.get_meta_window();
+        let parent = meta.get_transient_for();
+        if (!parent)
+            return;
+        let parentActor = parent.get_compositor_private();
+        if (!parentActor)
+            return;
+        if (!this._parentHasOtherAttachedDialog(parent, meta)) {
+            let texture = parentActor.get_texture();
+            Tweener.addTween(getWindowDimmer(texture),
+                             { dimFraction: 0.0,
+                               time: UNDIM_TIME,
+                               transition: 'linear'
+                             });
+        }
+    },
+
     _mapWindow : function(shellwm, actor) {
+        if (this._shouldAnimate() && actor
+            && actor.get_window_type() == Meta.CompWindowType.MODAL_DIALOG
+            && Meta.prefs_get_attach_modal_dialogs()
+            && actor.get_meta_window().get_transient_for()) {
+            actor.set_scale(1.0, 0.0);
+            actor.show();
+            this._mapping.push(actor);
+
+            Tweener.addTween(actor,
+                             { scale_y: 1,
+                               time: WINDOW_ANIMATION_TIME,
+                               transition: "easeOutQuad",
+                               onComplete: this._mapWindowDone,
+                               onCompleteScope: this,
+                               onCompleteParams: [shellwm, actor],
+                               onOverwrite: this._mapWindowOverwrite,
+                               onOverwriteScope: this,
+                               onOverwriteParams: [shellwm, actor]
+                             });
+            this._dimParentWindow(actor);
+            return;
+        }
         if (!this._shouldAnimate(actor)) {
             shellwm.completed_map(actor);
             return;
@@ -185,11 +317,46 @@ WindowManager.prototype = {
         }
     },
 
-    _destroyWindow : function(shellwm, actor) {
+    _destroyWindowOverwrite : function(shellwm, actor) {
+        if (this._removeEffect(this._mapping, actor)) {
+            shellwm.completed_destroy(actor);
+        }
+    },
+
+     _destroyWindow : function(shellwm, actor) {
+        while (actor && this._shouldAnimate()
+               && actor.get_window_type() == Meta.CompWindowType.MODAL_DIALOG
+               && actor.get_meta_window().get_transient_for()) {
+            this._undimParentWindow(actor);
+            if (!Meta.prefs_get_attach_modal_dialogs())
+                break;
+            actor.set_scale(1.0, 1.0);
+            actor.show();
+            this._mapping.push(actor);
+
+            Tweener.addTween(actor,
+                             { scale_y: 0,
+                               time: WINDOW_ANIMATION_TIME,
+                               transition: "easeOutQuad",
+                               onComplete: this._destroyWindowDone,
+                               onCompleteScope: this,
+                               onCompleteParams: [shellwm, actor],
+                               onOverwrite: this._destroyWindowOverwrite,
+                               onOverwriteScope: this,
+                               onOverwriteParams: [shellwm, actor]
+                             });
+            return;
+        }
         shellwm.completed_destroy(actor);
     },
-    
+
     _destroyWindowDone : function(shellwm, actor) {
+        if (actor && actor.get_window_type() == Meta.CompWindowType.MODAL_DIALOG &&
+            actor.get_meta_window().get_transient_for()) {
+            if (this._removeEffect(this._mapping, actor)) {
+                shellwm.completed_destroy(actor);
+            }
+        }
     },
 
     _switchWorkspace : function(shellwm, from, to, direction) {
index c6ac752781602598959b93d00e7c9b423013380b..3b78bd80fe150157ee50f82d1726fb6d76cddfa3 100644 (file)
@@ -154,6 +154,8 @@ static void
 gnome_shell_plugin_init (GnomeShellPlugin *shell_plugin)
 {
   g_setenv ("XDG_MENU_PREFIX", "gs-", TRUE);
+  meta_prefs_override_preference_location ("/apps/mutter/general/attach_modal_dialogs",
+                                           "/desktop/gnome/shell/windows/attach_modal_dialogs");
   meta_prefs_override_preference_location ("/apps/metacity/general/button_layout",
                                            "/desktop/gnome/shell/windows/button_layout");
 }